package com.tengju.bff.interfaces.covercharge.controller.admin;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.idanchuang.component.base.JsonResult;
import com.idanchuang.component.base.util.StringUtil;
import com.idanchuang.component.redis.util.DRedisLocks;
import com.tengju.bff.interfaces.covercharge.constant.*;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceRewardPunishDetail;
import com.tengju.bff.interfaces.covercharge.entity.vo.*;
import com.tengju.bff.interfaces.covercharge.enums.ProfitTypeEnum;
import com.tengju.bff.interfaces.covercharge.service.IServiceRewardPunishDetailService;
import com.tengju.bff.interfaces.covercharge.util.ExcelExportUtil;
import com.tengju.bff.interfaces.covercharge.util.ExcelReadUtil;
import com.tengju.bff.interfaces.covercharge.util.ZipUtils;
import com.tengju.bff.interfaces.covercharge.util.validator.ValidaUtil;
import com.tengju.bff.interfaces.shared.ApiResponse;
import com.tengju.bff.interfaces.shared.servlet.ManageEntrance;
import com.zoi7.component.core.exception.ServiceException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

/**
 * @Author: xx
 * @Description: 违约金申请相关controller
 * @Date: 2020/12/14 20:49
 */
@Api(value = "punish/apply", tags = "Admin违约金申请页相关")
@RestController
@Slf4j
@RequestMapping("/manage/punish/apply")
@ManageEntrance
public class AdminPunishApplyController {

    @Resource
    private IServiceRewardPunishDetailService serviceRewardPunishDetailService;


    @PostMapping("/getApplyInfo")
    @ApiOperation(value = "申请页查询", notes = "申请页查询")
    public ApiResponse<IPage<AdminPunishApplyVo>> getApplyInfo(@RequestBody AdminPunishApplyQuery adminPunishApplyQuery) {
        //校验是否有查询条件,若没有则默认创建时间为当天
        String startDate;
        try {
            if (adminPunishApplyQuery.getAgentId() == null && StringUtil.isBlank(adminPunishApplyQuery.getAccount())
                    && adminPunishApplyQuery.getIdCode() == null && StringUtil.isBlank(adminPunishApplyQuery.getApplyNo())
                    && adminPunishApplyQuery.getDealId() == null && adminPunishApplyQuery.getStatus() == null
                    && StringUtil.isBlank(adminPunishApplyQuery.getCreatedStartTime())
                    && StringUtil.isBlank(adminPunishApplyQuery.getSubmitStartTime())
                    && StringUtil.isBlank(adminPunishApplyQuery.getDoneStartTime())
                    && StringUtil.isBlank(adminPunishApplyQuery.getRevokeStartTime())) {
                startDate = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now());
                adminPunishApplyQuery.setCreatedStartTime(startDate);
            }
            return ApiResponse.newSuccess(serviceRewardPunishDetailService.getApplyInfo(adminPunishApplyQuery));
        } catch (Exception e) {
            log.error("[财务管理后台][申请页查询][查询失败,有异常抛出！]", e);
            return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "查询失败,请刷新重试或联系开发人员！");
        }
    }

    @PostMapping("/saveApplyInfo")
    @ApiOperation(value = "新增申请单", notes = "新增申请单")
    public ApiResponse<String> saveApplyInfo(@RequestBody AdminPunishApplySave adminPunishApplySave) {
        //校验参数
        ValidaUtil.baseReqParamCheck(adminPunishApplySave);
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_SAVE + adminPunishApplySave.getApplyNo(), 500, () -> {
            try {
                serviceRewardPunishDetailService.insertApply(adminPunishApplySave);
            } catch (ServiceException e) {
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_EXCEPTION.getCode(), e.getMessage());
            } catch (Exception e) {
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "添加失败！请联系开发人员处理");
            }
            return ApiResponse.newSuccess(adminPunishApplySave.getApplyNo());
        });
    }

    @PostMapping("/delApplyList")
    @ApiOperation(value = "批量删除申请单", notes = "批量删除申请单")
    public ApiResponse<?> delApply(@RequestBody AdminPunishApplyUpdate adminPunishApplyUpdateVo) {
        List<AdminPunishApplyVo> updateList = adminPunishApplyUpdateVo.getApplyList();
        if (CollectionUtil.isEmpty(updateList)) {
            log.info("[财务管理系统][奖惩申请页面][批量删除申请单][删除失败,请求list为空]");
            return ApiResponse.newFailure(CoverChargeErrorCode.PARAM_ERROR.getCode(), "请求参数缺失");
        }
        if (!RewardPunishStatusEnum.DELETE.getStatus().equals(adminPunishApplyUpdateVo.getStatus())) {
            log.info("[财务管理系统][奖惩申请页面][批量删除申请单][删除失败,请求状态不正确]");
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "请求状态不正确");
        }
        List<String> delApplyList = checkByApplyNo(updateList);
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_DEL_ + updateList, 500, () -> {
            try {
                for (String applyNo : delApplyList) {
                    serviceRewardPunishDetailService.delApplyByApplyId(applyNo, adminPunishApplyUpdateVo.getOperate());
                }
                return ApiResponse.newSuccess();
            } catch (Exception e) {
                log.error("[财务管理后台][批量删除申请单][批量删除失败,有异常抛出]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "批量删除失败！请及时联系开发人员处理");
            }
        });
    }


    @PostMapping("/delApplyById")
    @ApiOperation(value = "单个删除申请单", notes = "单个删除申请单")
    public ApiResponse<?> delApplyById(@RequestBody AdminPunishApplyActionVo delPunishApplyActionVo) {
        //1、基础参数校验
        if (delPunishApplyActionVo == null) {
            log.info("[财务管理系统][奖惩申请页面][单个删除申请单][删除失败,请求参数缺失!]");
            return ApiResponse.newFailure(CoverChargeErrorCode.PARAM_ERROR.getCode(), "删除失败,请求参数缺失!");
        }
        ValidaUtil.baseReqParamCheck(delPunishApplyActionVo);
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_DEL_ + delPunishApplyActionVo.getApplyNo() + "_" + delPunishApplyActionVo.getId(), 500, () -> {
            try {
                serviceRewardPunishDetailService.delApplyById(delPunishApplyActionVo.getId(), delPunishApplyActionVo.getApplyNo(), delPunishApplyActionVo.getOperate());
                return ApiResponse.newSuccess();
            } catch (ServiceException e) {
                log.info("[财务管理后台][奖惩申请页面][单个删除申请单][删除失败]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_FAIL.getCode(), e.getMessage());
            } catch (Exception e) {
                log.error("[财务管理后台][奖惩申请页面][单个删除申请单][删除失败,有异常抛出]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "单个删除失败，请及时联系开发人员");
            }
        });
    }


    @PostMapping("/submitApply")
    @ApiOperation(value = "批量提交申请单", notes = "批量提交申请单")
    public ApiResponse<?> submitApply(@RequestBody AdminPunishApplyUpdate adminPunishApplyUpdateVo) {
        List<AdminPunishApplyVo> submitList = adminPunishApplyUpdateVo.getApplyList();
        if (CollectionUtil.isEmpty(submitList)) {
            log.info("[财务管理系统][奖惩申请页面][批量提交申请单][提交失败,请求list为空]");
            return ApiResponse.newFailure(CoverChargeErrorCode.PARAM_ERROR.getCode(), "请求参数缺失");
        }
        if (!RewardPunishStatusEnum.CHECKING.getStatus().equals(adminPunishApplyUpdateVo.getStatus())) {
            log.info("[财务管理系统][奖惩申请页面][批量提交申请单][提交失败,请求状态不正确]");
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "请求状态不正确");
        }
        List<String> submitApplyList = checkByApplyNo(submitList);
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_SUB_ + submitApplyList, 500, () -> {
            try {
                for (String applyNo : submitApplyList) {
                    serviceRewardPunishDetailService.submitApplyByApplyId(applyNo, adminPunishApplyUpdateVo.getOperate());
                }
                return ApiResponse.newSuccess();
            } catch (ServiceException e) {
                log.error("[财务管理后台][批量提交申请单][提交失败,有异常抛出]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_FAIL.getCode(), e.getMessage());
            } catch (Exception e) {
                log.error("[财务管理后台][批量提交申请单][提交失败,有异常抛出]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "批量提交失败！请及时联系开发人员处理");
            }
        });
    }

    @PostMapping("/submitApplyById")
    @ApiOperation(value = "单个提交申请单", notes = "单个提交申请单")
    public ApiResponse<?> submitApplyById(@RequestBody AdminPunishApplyActionVo adminPunishApplyActionVo) {
        //1、基础参数校验
        if (adminPunishApplyActionVo == null) {
            log.info("[财务管理系统][奖惩申请页面][单个提交申请单][提交失败,请求参数缺失!]");
            return ApiResponse.newFailure(CoverChargeErrorCode.PARAM_ERROR.getCode(), "提交失败,请求参数缺失!");
        }
        ValidaUtil.baseReqParamCheck(adminPunishApplyActionVo);
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_SUB_ + adminPunishApplyActionVo.getApplyNo() + "_" + adminPunishApplyActionVo.getId(), 500, () -> {
            try {
                serviceRewardPunishDetailService.submitApplyById(adminPunishApplyActionVo.getId(), adminPunishApplyActionVo.getApplyNo(), adminPunishApplyActionVo.getOperate());
                return ApiResponse.newSuccess();
            } catch (ServiceException e) {
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_FAIL.getCode(), e.getMessage());
            } catch (Exception e) {
                log.error("[财务管理后台][奖惩申请页面][单个提交申请单][提交失败,有异常抛出]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "提交失败！请及时联系开发人员处理");
            }
        });
    }

    @PostMapping("/updateApply")
    @ApiOperation(value = "编辑申请单", notes = "编辑申请单")
    public ApiResponse<?> updateApply(@RequestBody AdminPunishApplySave adminPunishApplySave) {
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_UPDATE_ + adminPunishApplySave.getApplyNo() + "_" + adminPunishApplySave.getId(), 500, () -> {
            try {
                serviceRewardPunishDetailService.updateApply(adminPunishApplySave);
                return ApiResponse.newSuccess();
            } catch (ServiceException e) {
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_FAIL.getCode(), e.getMessage());
            } catch (Exception e) {
                log.error("[财务管理后台][奖惩申请页面][单个提交申请单][提交失败,有异常抛出]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "提交失败！请及时联系开发人员处理");
            }
        });
    }

    @PostMapping("/inputApply")
    @ApiOperation(value = "导入申请单", notes = "导入申请单")
    public ApiResponse<?> inputApply(@RequestBody AdminPunishImport adminPunishImport) {
        HttpClient client = new HttpClient();
        client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
        // 设置连接超时时间为10秒（连接初始化时间）
        client.getHttpConnectionManager().getParams().setConnectionTimeout(10000);
        GetMethod method = new GetMethod(adminPunishImport.getUrl());
        List<String[]> allExcelInfo = null;
        try {
            int statusCode = client.executeMethod(method);
            if (statusCode != HttpStatus.SC_OK) {
                log.info("[财务管理后台][奖惩申请页面][申请单导入失败,申请单号：{},表格处理状态：{}]", adminPunishImport.getApplyNo(), statusCode);
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_FAIL.getCode(), "表格导入失败,请重试或联系开发人员！");
            }
            allExcelInfo = ExcelReadUtil.getAllExcelInfo(method.getResponseBodyAsStream(), !adminPunishImport.getUrl().contains("xlsx"), null, null, "0", "100000", 0);
        } catch (Exception e) {
            log.error("[财务管理后台][奖惩申请页面][申请单导入失败,有异常抛出！申请单号：{}]", adminPunishImport.getApplyNo(), e);
        } finally {
            client.getHttpConnectionManager().closeIdleConnections(1);
        }
        if (StringUtils.isEmpty(allExcelInfo)) {
            log.info("[财务管理后台][奖惩申请页面][申请单导入失败,未检测到导入文件!申请单号：{}]", adminPunishImport.getApplyNo());
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_FAIL.getCode(), "未检测到导入文件,请重试或联系开发人员！");
        }
        List<String[]> finalAllExcelInfo = allExcelInfo;
        return DRedisLocks.runWithLock(BizConstants.REWARD_PUNISH_APPLY_IMPORT_ + adminPunishImport.getFileName(), 10000, () -> {
            try {
                PunishApplyImportTaskResult taskResult = serviceRewardPunishDetailService.importPunishApplyTask(finalAllExcelInfo.size() - 3, adminPunishImport);
                if (taskResult.isTaskResult()) {
                    try {
                        serviceRewardPunishDetailService.importPunishApply(taskResult.getTaskNo(), finalAllExcelInfo, adminPunishImport);
                    } catch (Exception e) {
                        log.error("[财务管理后台][奖惩申请页面][申请单导入失败,有异常抛出!申请单号：{}]", adminPunishImport.getApplyNo(), e);
                    }
                    return ApiResponse.newSuccess("导入成功，请去日志查询页面查看执行结果。");
                }
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), taskResult.getErrorMsg());
            } catch (Exception e) {
                log.error("[财务管理后台][奖惩申请页面][申请单导入失败,有异常抛出！]", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "导入文件失败,请联系开发人员处理！");
            }
        });
    }

    @RequestMapping("/exportApply")
    @ApiOperation(value = "导出申请单", notes = "导出申请单")
    public void exportApply(@RequestBody AdminPunishApplyQuery adminPunishApplyQuery, HttpServletResponse response) {
        try {
            IPage<AdminPunishApplyVo> punishApplyVoPageTotal = serviceRewardPunishDetailService.getApplyInfo(adminPunishApplyQuery);
            log.info("[财务管理后台][导出奖惩申请发放列表][导出用户:{}]", adminPunishApplyQuery.getOperate());
            long count = punishApplyVoPageTotal.getTotal();
            //定义多个excel
            List<Workbook> workbookList = new ArrayList<>();
            if (count != 0) {
                Integer page = serviceRewardPunishDetailService.getPage(count);
                //循环遍历,分页查询
                for (int i = 1; i <= page; i++) {
                    adminPunishApplyQuery.setCurrent(i);
                    adminPunishApplyQuery.setSize(PageSize.REWARD_EXPORT_PAGE_SIZE);
                    IPage<AdminPunishApplyVo> punishApplyVoPage = serviceRewardPunishDetailService.getApplyInfo(adminPunishApplyQuery);
                    ExcelExportUtil excel = new ExcelExportUtil();
                    excel.createRow(0);
                    excel.setCell(0, "申请单号");
                    excel.setCell(1, "用户ID");
                    excel.setCell(2, "注册号码");
                    excel.setCell(3, "代理名称");
                    excel.setCell(4, "等级");
                    excel.setCell(5, "用户身份");
                    excel.setCell(6, "处理类型");
                    excel.setCell(7, "违规内容");
                    excel.setCell(8, "扣除金额");
                    excel.setCell(9, "创建时间");
                    excel.setCell(10, "提交时间");
                    excel.setCell(11, "完成时间");
                    excel.setCell(12, "取消时间");
                    excel.setCell(13, "经办人");
                    excel.setCell(14, "状态");
                    excel.setCell(15, "创建人");
                    excel.setCell(16, "审核人");
                    int index = 1;

                    for (AdminPunishApplyVo adminPunishApplyVo : punishApplyVoPage.getRecords()) {
                        excel.createRow(index);
                        excel.setCell(0, adminPunishApplyVo.getApplyNo());
                        excel.setCell(1, adminPunishApplyVo.getIdCode() + "");
                        //获取用户注册手机号
                        excel.setCell(2, StringUtil.isBlank(adminPunishApplyVo.getRegisterMobile()) ? "" : adminPunishApplyVo.getRegisterMobile());
                        excel.setCell(3, StringUtil.isBlank(adminPunishApplyVo.getName()) ? "" : adminPunishApplyVo.getName());
                        excel.setCell(4, StringUtil.isBlank(adminPunishApplyVo.getLevel()) ? "" : adminPunishApplyVo.getLevel());
                        excel.setCell(5, StringUtil.isBlank(adminPunishApplyVo.getRole()) ? "" : adminPunishApplyVo.getRole());
                        excel.setCell(6, StringUtil.isBlank(adminPunishApplyVo.getDealValue()) ? "" : adminPunishApplyVo.getDealValue());
                        excel.setCell(7, StringUtil.isBlank(adminPunishApplyVo.getViolateValue()) ? "" : adminPunishApplyVo.getViolateValue());
                        excel.setCell(8, adminPunishApplyVo.getMoney() + "");
                        excel.setCell(9, adminPunishApplyVo.getCreatedTime());
                        excel.setCell(10, StringUtil.isBlank(adminPunishApplyVo.getSubmitTime()) ? "" : adminPunishApplyVo.getSubmitTime());
                        excel.setCell(11, StringUtil.isBlank(adminPunishApplyVo.getDoneTime()) ? "" : adminPunishApplyVo.getDoneTime());
                        excel.setCell(12, StringUtil.isBlank(adminPunishApplyVo.getRevokeTime()) ? "" : adminPunishApplyVo.getRevokeTime());
                        excel.setCell(13, StringUtil.isBlank(adminPunishApplyVo.getAgentName()) ? "" : adminPunishApplyVo.getAgentName());
                        RewardPunishStatusEnum rewardPunishStatusEnum = RewardPunishStatusEnum.getStatusDesc(adminPunishApplyVo.getStatus());
                        excel.setCell(14, rewardPunishStatusEnum == null ? "" : rewardPunishStatusEnum.getMsg());
                        excel.setCell(15, adminPunishApplyVo.getCreateBy());
                        excel.setCell(16, adminPunishApplyVo.getDealBy());
                        index++;
                    }
                    workbookList.add(excel.getWorkbook());
                }
            }
            //获取当前时间
            String zipName = "奖惩申请_" + DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now()) + ".zip";
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
            //文件流导出
            ZipOutputStream out = null;
            try {
                out = new ZipOutputStream(response.getOutputStream());
            } catch (IOException e) {
                log.error("[财务管理后台][申请页面导出][zip压缩导出出现错误]", e);
            }
            try {
                int zipIndex = 1;
                for (Workbook workbook : workbookList) {
                    ZipUtils.doZip(zipIndex + ".xls", workbook, out, "");
                    response.flushBuffer();
                    zipIndex += 1;
                }
            } catch (Exception e) {
                log.error("[违约金][审核页面导出][zip压缩导出出现错误]", e);
            } finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                } catch (IOException e) {
                    log.error("[违约金][审核页面导出][zip压缩关闭流出现错误]", e);
                }
            }
        } catch (Exception e) {
            log.error("[违约金][申请页面导出][失败信息]", e);
        }
    }

    /**
     * list去重
     *
     * @param updateList 需要去重的list
     * @return 申请单号集合
     */
    List<String> checkByApplyNo(List<AdminPunishApplyVo> updateList) {
        //给List去重
        List<String> applyNoList = new ArrayList<>();
        for (AdminPunishApplyVo adminPunishApplyVo : updateList) {
            applyNoList.add(adminPunishApplyVo.getApplyNo());
        }
        applyNoList = applyNoList.stream().distinct().collect(Collectors.toList());
        return applyNoList;
    }

}
